
#import <Cocoa/Cocoa.h>

#import <OpenGL/OpenGL.h>
#import <OpenGL/gl.h>
#import <OpenGL/glu.h>

#import <os_host.h>

int MyApplicationMain(int argc, const char **argv);

@interface MyApplication : NSApplication
{
	bool shouldKeepRunning;
}

- (void)run;
- (void)terminate:(id)sender;

@end

@interface Host_GLView : NSOpenGLView
{
	int colorBits, depthBits;
	BOOL runningFullScreen;
	NSDictionary *originalDisplayMode;
}

- (id) initWithFrame:(NSRect)frame colorBits:(int)numColorBits
		   depthBits:(int)numDepthBits fullscreen:(BOOL)runFullScreen;
- (void) reshape;
- (void) drawRect:(NSRect)rect;
- (BOOL) isFullScreen;
- (BOOL) setFullScreen:(BOOL)enableFS inFrame:(NSRect)frame;
- (void) dealloc;

@end

int MyApplicationMain(int argc, const char **argv)
{
	NSApplication *app;
	
	
	[NSApplication sharedApplication];
	//[NSBundle loadNibNamed:@"MainMenu.nib" owner:NSApp];
	//[NSApp run];
	
	
	
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	
	NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
	Class principalClass =
	NSClassFromString([infoDictionary objectForKey:@"NSPrincipalClass"]);
	NSApplication *applicationObject = [principalClass sharedApplication];
	
	//NSString *mainNibName = [infoDictionary objectForKey:@"NSMainNibFile"];
	//NSNib *mainNib = [[NSNib alloc] initWithNibNamed:mainNibName bundle:[NSBundle mainBundle]];
	//[mainNib instantiateNibWithOwner:applicationObject topLevelObjects:nil];
	
	while(1)	
//	if ([applicationObject respondsToSelector:@selector(run)])
	{
		
		printf("looping\n");
		
		[applicationObject
		 performSelectorOnMainThread:@selector(run)
		 withObject:nil
		 waitUntilDone:YES];
	
		[applicationObject
		 run:nil
		 ];
	
	}
	
	//[mainNib release];
	[pool release];
	
	return 0;
}

@implementation MyApplication

- (void)run
{
	//	[self finishLaunching];
	[[NSNotificationCenter defaultCenter]
	 postNotificationName:NSApplicationWillFinishLaunchingNotification
	 object:NSApp];
	[[NSNotificationCenter defaultCenter]
	 postNotificationName:NSApplicationDidFinishLaunchingNotification
	 object:NSApp];
	
	shouldKeepRunning = YES;
	do
	{
		NSEvent *event =
		[self
		 nextEventMatchingMask:NSAnyEventMask
		 untilDate:[NSDate distantFuture]
		 inMode:NSDefaultRunLoopMode
		 dequeue:YES];
		
		[self sendEvent:event];
		[self updateWindows];
	} while (shouldKeepRunning);
}

- (void)terminate:(id)sender
{
	shouldKeepRunning = NO;
}

@end



@interface AppController : NSObject {
}
- (IBAction)doSomething:(id)sender;
@end

@implementation AppController
- (IBAction)doSomething:(id)sender;
{
	//printf("Button clicked!\n");
	NSWindow *infoWindow;
	
	infoWindow = NSGetCriticalAlertPanel( @"Initialization failed",
                                         @"Failed to initialize OpenGL",
                                         @"OK", nil, nil );
	[ NSApp runModalForWindow:infoWindow ];
	[ infoWindow close ];
	[ NSApp terminate:self ];
}
@end

int os_init(int argc, char **args){
	NSRect frame = NSMakeRect(0, 0, 640, 480);
	
	AppController *controller = [[AppController alloc] init];
	
	[[NSApplication sharedApplication] setDelegate:controller];
	NSWindow* window  = [[NSWindow alloc] initWithContentRect:frame
													styleMask:NSBorderlessWindowMask|NSClosableWindowMask|NSMiniaturizableWindowMask|NSResizableWindowMask
													  backing:NSBackingStoreBuffered
														defer:NO];
	[window setBackgroundColor:[NSColor blueColor]];

	Host_GLView *view = [ [Host_GLView alloc] initWithFrame : NSMakeRect( 0, 0, 640, 480) ];
	[ view initGL nil];
	[ [window contentView]  addSubview: view ];
	
	NSButton *button = [ [ NSButton alloc ] initWithFrame: NSMakeRect( 30.0, 20.0, 80.0, 50.0 ) ];
	[ button setBezelStyle:NSRoundedBezelStyle];
	[ button setTitle: @"Click" ];
	[ button setAction:@selector(doSomething:)];
	[ button setTarget:controller];
	[ [ window contentView ] addSubview: button ];
	
	[window makeKeyAndOrderFront:NSApp];
	
	MyApplicationMain(argc,  (const char **) args);
	
	return 0;
}


/*
 * Original Windows comment:
 * "This code was created by Jeff Molofee 2000
 * A HUGE thanks to Fredric Echols for cleaning up
 * and optimizing the base code, making it more flexible!
 * If you've found this code useful, please let me know.
 * Visit my site at nehe.gamedev.net"
 * 
 * Cocoa port by Bryan Blackburn 2002; www.withay.com
 */



@interface Host_GLView (InternalMethods)
- (NSOpenGLPixelFormat *) createPixelFormat:(NSRect)frame;
- (void) switchToOriginalDisplayMode;
- (BOOL) initGL;
@end

@implementation Host_GLView

- (id) initWithFrame:(NSRect)frame colorBits:(int)numColorBits
		   depthBits:(int)numDepthBits fullscreen:(BOOL)runFullScreen
{
	NSOpenGLPixelFormat *pixelFormat;
	
	colorBits = numColorBits;
	depthBits = numDepthBits;
	runningFullScreen = runFullScreen;
	originalDisplayMode = (NSDictionary *) CGDisplayCurrentMode(
																kCGDirectMainDisplay );
	pixelFormat = [ self createPixelFormat:frame ];
	if( pixelFormat != nil )
	{
		self = [ super initWithFrame:frame pixelFormat:pixelFormat ];
		[ pixelFormat release ];
		if( self )
		{
			[ [ self openGLContext ] makeCurrentContext ];
			if( runningFullScreen )
				[ [ self openGLContext ] setFullScreen ];
			[ self reshape ];
			if( ![ self initGL ] )
			{
				[ self clearGLContext ];
				self = nil;
			}
		}
	}
	else
		self = nil;
	
	return self;
}


/*
 * Create a pixel format and possible switch to full screen mode
 */
- (NSOpenGLPixelFormat *) createPixelFormat:(NSRect)frame
{
	NSOpenGLPixelFormatAttribute pixelAttribs[ 16 ];
	int pixNum = 0;
	NSDictionary *fullScreenMode;
	NSOpenGLPixelFormat *pixelFormat;
	
	pixelAttribs[ pixNum++ ] = NSOpenGLPFADoubleBuffer;
	pixelAttribs[ pixNum++ ] = NSOpenGLPFAAccelerated;
	pixelAttribs[ pixNum++ ] = NSOpenGLPFAColorSize;
	pixelAttribs[ pixNum++ ] = colorBits;
	pixelAttribs[ pixNum++ ] = NSOpenGLPFADepthSize;
	pixelAttribs[ pixNum++ ] = depthBits;
	
	if( runningFullScreen )  // Do this before getting the pixel format
	{
		pixelAttribs[ pixNum++ ] = NSOpenGLPFAFullScreen;
		fullScreenMode = (NSDictionary *) CGDisplayBestModeForParameters(
																		 kCGDirectMainDisplay,
																		 colorBits, frame.size.width,
																		 frame.size.height, NULL );
		CGDisplayCapture( kCGDirectMainDisplay );
		CGDisplayHideCursor( kCGDirectMainDisplay );
		CGDisplaySwitchToMode( kCGDirectMainDisplay,
							  (CFDictionaryRef) fullScreenMode );
	}
	pixelAttribs[ pixNum ] = 0;
	pixelFormat = [ [ NSOpenGLPixelFormat alloc ]
                   initWithAttributes:pixelAttribs ];
	
	return pixelFormat;
}


/*
 * Enable/disable full screen mode
 */
- (BOOL) setFullScreen:(BOOL)enableFS inFrame:(NSRect)frame
{
	BOOL success = FALSE;
	NSOpenGLPixelFormat *pixelFormat;
	NSOpenGLContext *newContext;
	
	[ [ self openGLContext ] clearDrawable ];
	if( runningFullScreen )
		[ self switchToOriginalDisplayMode ];
	runningFullScreen = enableFS;
	pixelFormat = [ self createPixelFormat:frame ];
	if( pixelFormat != nil )
	{
		newContext = [ [ NSOpenGLContext alloc ] initWithFormat:pixelFormat
												   shareContext:nil ];
		if( newContext != nil )
		{
			[ super setFrame:frame ];
			[ super setOpenGLContext:newContext ];
			[ newContext makeCurrentContext ];
			if( runningFullScreen )
				[ newContext setFullScreen ];
			[ self reshape ];
			if( [ self initGL ] )
				success = TRUE;
		}
		[ pixelFormat release ];
	}
	if( !success && runningFullScreen )
		[ self switchToOriginalDisplayMode ];
	
	return success;
}


/*
 * Switch to the display mode in which we originally began
 */
- (void) switchToOriginalDisplayMode
{
	CGDisplaySwitchToMode( kCGDirectMainDisplay,
                          (CFDictionaryRef) originalDisplayMode );
	CGDisplayShowCursor( kCGDirectMainDisplay );
	CGDisplayRelease( kCGDirectMainDisplay );
}


/*
 * Initial OpenGL setup
 */
- (BOOL) initGL
{ 
	glShadeModel( GL_SMOOTH );                // Enable smooth shading
	glClearColor( 0.0f, 0.0f, 0.0f, 0.5f );   // Black background
	glClearDepth( 1.0f );                     // Depth buffer setup
	glEnable( GL_DEPTH_TEST );                // Enable depth testing
	glDepthFunc( GL_LEQUAL );                 // Type of depth test to do
	// Really nice perspective calculations
	glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
	
	return TRUE;
}


/*
 * Resize ourself
 */
- (void) reshape
{ 
	NSRect sceneBounds;
	
	[ [ self openGLContext ] update ];
	sceneBounds = [ self bounds ];
	// Reset current viewport
	glViewport( 0, 0, sceneBounds.size.width, sceneBounds.size.height );
	glMatrixMode( GL_PROJECTION );   // Select the projection matrix
	glLoadIdentity();                // and reset it
	// Calculate the aspect ratio of the view
	gluPerspective( 45.0f, sceneBounds.size.width / sceneBounds.size.height,
                   0.1f, 100.0f );
	glMatrixMode( GL_MODELVIEW );    // Select the modelview matrix
	glLoadIdentity();                // and reset it
}


/*
 * Called when the system thinks we need to draw.
 */
- (void) drawRect:(NSRect)rect
{
	// Clear the screen and depth buffer
	glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
	glLoadIdentity();   // Reset the current modelview matrix
	[ [ self openGLContext ] flushBuffer ];
}


/*
 * Are we full screen?
 */
- (BOOL) isFullScreen
{
	return runningFullScreen;
}


/*
 * Cleanup
 */
- (void) dealloc
{
	if( runningFullScreen )
		[ self switchToOriginalDisplayMode ];
	[ originalDisplayMode release ];
}

@end





